package it.unipg.bipod;

import java.io.*;
import java.util.*;
import javax.faces.context.FacesContext;

/**
 * ResManager gestisce le risorse di BiPoD.<br>
 * In ogni momento esiste una sola istanza di ResManager, recuperabile tramite getInstance().
 * Piu' precisamente ResManager legge alcuni file di impostazioni e ne estrae i contenuti:
 * <ul>
 *   <li><b>WEB-INF/settings/data.ini</b>: file di proprieta' scritto nella notazione standard
 *   di java che contiene le impostazione dello strato di accesso ai dati. Le impostazioni
 *   si possono accedere tramite {@link ResManager#getDataSettings()}.</li>
 *   <li><b>WEB-INF/settings/application.ini</b>: file di proprieta' scritto nella notazione standard
 *   di java che contiene le impostazione dello strato di logica applicativa. Le impostazioni
 *   si possono accedere tramite {@link ResManager#getApplicationSettings()}.</li>
 *   <li><b>WEB-INF/settings/presentation.ini</b>: file di proprieta' scritto nella notazione standard
 *   di java che contiene le impostazione dello strato di presentazione. Le impostazioni
 *   si possono accedere tramite {@link ResManager#getPresentationSettings()}.</li>
 * </ul>
 * Inoltre ResManager permette di accedere ai file di testo contenuti in WEB-INF/resources
 * tramite il metodo {@link ResManager#getResource()}.
 * @author LorenzoPorzi
 *
 */
public class ResManager {
	private Properties dataSettings;
	private Properties applicationSettings;
	private Properties presentationSettings;
	private Hashtable<String, String> resources;
	private String settingsFolder;
	private String resourcesFolder;
	
	// Costruttore privato e classe privata necessari per il pattern singleton
	
	private ResManager() {
		resources = new Hashtable<String, String>();
		settingsFolder = FacesContext.getCurrentInstance().getExternalContext().getRealPath("WEB-INF/settings");
		resourcesFolder = FacesContext.getCurrentInstance().getExternalContext().getRealPath("WEB-INF/resources");
		
		dataSettings = null;
		applicationSettings = null;
		presentationSettings = null;
	}
	
	private static class SingletonResManager {
		private static final ResManager INSTANCE = new ResManager();
	}
	
	/* ----------------------------- 
	 * Metodi pubblici di ResManager
	 * ----------------------------- */
	
	/**
	 * Restituisce l'istanza di default di ResManager.
	 * 
	 * @return l'istanza di default di ResManager.
	 */
	public static ResManager getInstance() {
		return SingletonResManager.INSTANCE;
	}
	
	/**
	 * Carica la risorsa avente il nome specificato, leggendo il file ad essa associato.
	 * 
	 * @param nome il nome della risorsa da caricare.
	 * @return la risorsa caricata.
	 */
	private String loadResource(String nome) {
		FileInputStream file = null;
		BufferedReader in = null;
		
		try {
			file = new FileInputStream(resourcesFolder + File.separatorChar + nome + ".res");
			in = new BufferedReader(new InputStreamReader(file));
			
			StringBuffer res = new StringBuffer();
			String line;
			
			while ((line = in.readLine()) != null)
				res.append(line + "\n");
			
			file.close();
			in.close();
			
			return res.toString();			
		} catch (IOException e) {
			return null;
		}
	}

	/**
	 * Recupera le impostazioni dello strato di accesso ai dati.
	 * 
	 * @return un oggetto {@link java.util.Properties} contenente le impostazioni
	 * @throws IOException
	 */
	public Properties getDataSettings() throws IOException {
		if (dataSettings == null) {
			// Carica dataSettings
			dataSettings = new Properties();
			dataSettings.load(new FileInputStream(settingsFolder + File.separatorChar + "data.ini"));
		}
		
		return dataSettings;
	}

	/**
	 * Recupera le impostazioni della logica applicativa.
	 * 
	 * @return un oggetto {@link java.util.Properties} contenente le impostazioni
	 * @throws IOException
	 */
	public Properties getApplicationSettings() throws IOException {
		if (applicationSettings == null) {
			// Carica applicationSettings
			applicationSettings = new Properties();
			applicationSettings.load(new FileInputStream(settingsFolder + File.separatorChar + "application.ini"));
		}
		
		return applicationSettings;
	}
	
	/**
	 * Recupera le impostazioni dello strato di presentazione.
	 * 
	 * @return un oggetto {@link java.util.Properties} contenente le impostazioni
	 * @throws IOException
	 */
	public Properties getPresentationSettings() throws IOException {
		if (presentationSettings == null) {
			// Carica applicationSettings
			presentationSettings = new Properties();
			presentationSettings.load(new FileInputStream(settingsFolder + File.separatorChar + "presentation.ini"));
		}
		
		return presentationSettings;
	}
	
	/**
	 * Carica il file WEB-INF/resources/{nome}.res dove {nome} è il parametro
	 * di questo metodo.<br>
	 * Notare che le risorse vengono lette solo la prima volta che vengono richieste,
	 * poi vengono recuperate da una cache.
	 * 
	 * @param nome il nome della risorsa da caricare
	 * @return il contenuto della risorsa caricata.
	 */
	public String getResource(String nome) {
		// Controlla se la risorsa è già stata caricata
		if (resources.containsKey(nome))
			return resources.get(nome);
		
		// Carica la risorsa
		String resource = loadResource(nome);
		if (resource == null)
			return null; // La risorsa non esiste
		
		// Memorizzo la risorsa e la restituisco
		resources.put(nome, resource);
		return resource;
	}
}